iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
Mobile Development

Flutter基礎入門系列 第 24

【Day 24】接續前一篇的內容:FormField實作篇

  • 分享至 

  • xImage
  •  

上一篇:【Day 23】增加功能:利用FormField新增資料
本篇中將會把昨天的內容實際應用在Schedrag程式中。那麼就直接來看程式,再來做說明吧!


詳細程式碼

Todo頁面的新增按鈕

presentation/pages/todo.dart中,設定按下右下角的懸浮按鈕會開啟一個暫時性的widget(利用Navigator.push),並且新頁面中的物件為EntryForm,並輸入現在開啟的資料庫作為參數,以便後續做新增資料的動作。

floatingActionButton: FloatingActionButton(
  // add new timeblock
  onPressed: () {
    Navigator.push(
        context,
        MaterialPageRoute(
          builder: (context) => EntryForm(db: timeblocksdb),
        ));
  },
  child: const Icon(Icons.add),
),

新增資料的頁面:EntryForm

下列為程式的主要框架,因內容較長,故在此做部份函式的省略,而省略部份於下方將會詳細說明。

import 'package:flutter/material.dart';
import 'package:schedrag/data/models/child_blocks.dart';

enum Tags { name, category, notes }

class EntryForm extends StatefulWidget {
  final TimeBlocksDb? db;
  const EntryForm({super.key, required this.db});

  @override
  State<EntryForm> createState() => _EntryFormState(db);
}

class _EntryFormState extends State<EntryForm> {
  final TimeBlocksDb? db;
  final _formKey = GlobalKey<FormState>();
  List<TextEditingController> controllers = [...];
  
  _EntryFormState(this.db);

  @override
  void dispose() {...}

  @override
  Widget build(context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("Add New Entry"),
      ),
      body: Form(...),
      floatingActionButton: FloatingActionButton(...),
    );
  }
}

Controller

此部份參考了官方的Cookbook - Retrieve the value of a text field
在這裡使用的TextEditingController可用於取得TextFormFieldTextField類別的輸入資訊。至於該如何讓各個FormField知道該使用哪一個controller,則是在TextFormField的controller property中設定。

List<TextEditingController> controllers = [
  TextEditingController(),
  TextEditingController(),
  TextEditingController()
];

// set controller
TextFormField(
  ...
  controller: controllers[0],
  ...
)

dispose

這部份是用於當EntryForm物件結束使用並移除資料時,剛剛建立的controller也能一起順利移除暫存資料。

@override
void dispose() {
  for (var controller in controllers) {
    controller.dispose();
  }
  super.dispose();
}

Form

此部份參考了官方的Cookbook - Build a form with validation
筆者希望使用者在新增資料時,name一欄不是空白,因此Name的TextFormField在validator property中設定了欄位輸入時的規則,而autovalidateMode則可以決定該在哪些時候去檢查輸入內容。關於_formKey該如何使用,將在下方談論新增資料按鈕時介紹。

body: Form(
  key: _formKey,
  child: Column(
    children: [
      TextFormField(
        decoration: const InputDecoration(
          icon: Icon(Icons.abc_rounded),
          labelText: "Name *",
        ),
        validator: (value) {
          return (value == null || value.isEmpty)
              ? "new block must have a name"
              : null;
        },
        controller: controllers[Tags.name.index],
        autovalidateMode: AutovalidateMode.onUnfocus,
      ),
      TextFormField(
        decoration: const InputDecoration(
          icon: Icon(Icons.category_rounded),
          labelText: "Category",
        ),
        controller: controllers[Tags.category.index],
      ),
      TextFormField(
        decoration: const InputDecoration(
          icon: Icon(Icons.sticky_note_2_rounded),
          labelText: "Notes",
        ),
        controller: controllers[Tags.notes.index],
      ),
    ],
  ),
),

新增按鈕FloatingActionButton

\_EntryFormState類別的最初建立時,設了一個property: _formKey,想驗證前面的FormField是否輸入符合要求,便可以使用_formKey.currentState來判斷它的true/false。

那麼這個布林值又是怎麼設定的呢?這其實由FormState的一個函式:validate()來自動調整的。validate()將會去跑Form裡物件的validator(),如上方在name所建立的。若有任何一個validator()回傳為false,validate()將會設_formKey.currentState為false,反之,若validator()全為true,validate()會將_formKey.currentState設為true。

validate()為true時,代表使用者輸入的內容符合要求,則將新資料新增至資料庫。最後,再將現在所在的頁面EntryForm從Navigator中pop出來,這部份的程式就完成啦!

final _formKey = GlobalKey<FormState>();

floatingActionButton: FloatingActionButton(
  onPressed: () {
    if (db != null && _formKey.currentState!.validate()) {
      db?.insert(TimeBlock.detail(
          name: controllers[0].text,
          category: controllers[1].text,
          notes: controllers[2].text));
      Navigator.pop(context);
    }
  },
  child: const Icon(Icons.add),
),

今天的內容就到這裡結束了,謝謝閱讀到這裡的讀者。
有任何問題或想說的都歡迎留言及email,明天會繼續努力的!


上一篇
【Day 23】增加功能:利用FormField新增資料
下一篇
【Day 25】日期與時間的輸入:DateTime
系列文
Flutter基礎入門30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言